/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package id3.controllers;

import id3.models.RowData;
import id3.utils.Constants;
import id3.utils.Utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 *
 * @author tungck
 */
public class ContinuousToDiscrete {

    private static float[] position;
    public static int[] arrIndexAttrCont = {1, 2, 7, 10, 13, 14};

    public static float[] getPosition() {
        return position;
    }

    public static ArrayList<RowData> updateData(ArrayList<RowData> data_training) {
        ArrayList<RowData> data = Utils.cloneData(data_training);
        position = new float[arrIndexAttrCont.length];
        ArrayList<RowData> dataProcessed = new ArrayList<>();
        for (int i = 0; i < arrIndexAttrCont.length; i++) {
            position[i] = positionGainMax(data, arrIndexAttrCont[i]);
        }

        for (RowData row : data) {
            ArrayList<String> newRow = row.getRow();
            for (int i = 0; i < arrIndexAttrCont.length; i++) {
                float value = getContValue(row.getRow().get(arrIndexAttrCont[i]));
                if (!Float.isNaN(value) && value <= position[i]) {
                    newRow.set(arrIndexAttrCont[i], Constants.LOW);
                } else if (!Float.isNaN(value)){
                    newRow.set(arrIndexAttrCont[i], Constants.HIGHT);
                }
            }
            dataProcessed.add(new RowData(newRow));

        }
        return dataProcessed;
    }

    private static ArrayList<RowData> sortValueOfAttr(ArrayList<RowData> data, int indexAttr) {

        ArrayList<RowData> dataToSort;
        dataToSort = Utils.cloneData(data);
        Collections.sort(dataToSort, new Comparator<RowData>() {

            @Override
            public int compare(RowData o1, RowData o2) {
                float a1=0f,a2=0f;
                try {
                    a1=Float.parseFloat(o1.getRow().get(indexAttr));
                } catch (Exception ex) {
                }
                try {
                    a2=Float.parseFloat(o2.getRow().get(indexAttr));
                } catch (Exception ex) {
                }
                return Float.compare(a1, a2);
            }
        });
        return dataToSort;
    }

    //tra lai gia tri float neu kieu do la float ko thi tra lai Float.NaN
    public static float getContValue(String value) {

        try {
            float a = Float.parseFloat(value);
            return a;
        } catch (Exception e) {

        }
        return Float.NaN;
    }

    //tra lai mang cac diem ma thuoc tinh thu indexAttr lam thay doi gia tri label
    private static ArrayList<Float> getValueChangeLabel(ArrayList<RowData> data, int indexAttr) {

        ArrayList<RowData> dataSorted=Utils.cloneData(data);
        ArrayList<Float> positions = new ArrayList<>();
        int index = 0;
        String label = null;
        float pre = Float.NaN;
        for (int i = 0; i < dataSorted.size(); i++) {
            RowData row_i = dataSorted.get(i);
            index = i;
            pre = getContValue(row_i.getRow().get(indexAttr));
            if (!Float.isNaN(pre)) {
                label = row_i.getRow().get(Constants.NUMBER_ATTRIBUTE - 1);
                break;
            }
        }
        float current;
        for (int i = index; i < dataSorted.size(); i++) {
            RowData row = dataSorted.get(i);
            current = getContValue(row.getRow().get(indexAttr));
            if (!Float.isNaN(current)) {
                if (!row.getRow().get(Constants.NUMBER_ATTRIBUTE - 1).equals(label)) {
                    positions.add((pre + current) / 2);
                    label = row.getRow().get(Constants.NUMBER_ATTRIBUTE - 1);
                }
                pre = current;
            }

        }
        return positions;
    }

    //tra lai gia tri cua diem gain max
    public static float positionGainMax(ArrayList<RowData> data_training, int indexAttr) {
        float gainMax = Float.NaN;
        ArrayList<RowData> data = Utils.cloneData(data_training);
        ArrayList<RowData> dataSorted = sortValueOfAttr(data, indexAttr);
        ArrayList<Float> pointChangeLabel = getValueChangeLabel(dataSorted, indexAttr);
//        System.out.println("[positionGainMax] : "+gainMax);
        if (pointChangeLabel.size() == 0) {
            return Float.NaN; // bo du lieu chi co mot nhan
        }//        System.out.println("[positionGainMax] : "+gainMax);
        gainMax = calInfoGain(dataSorted, indexAttr, pointChangeLabel.get(0));
        float iMax = pointChangeLabel.get(0);
        //bo du lieu co nhieu hon 1 diem thay doi nhan
        if (pointChangeLabel.size() > 1) {
            for (int i = 1; i < pointChangeLabel.size(); i++) {
                float cur_gain = calInfoGain(dataSorted, indexAttr, pointChangeLabel.get(i));
                if (gainMax < cur_gain) {
                    gainMax = cur_gain;
                    iMax = pointChangeLabel.get(i);
                }
            }
        }
        return iMax;
    }

    private static float calInfoGain(ArrayList<RowData> data, int attrIndex, float position) {

        ArrayList<RowData> dataSorted ;
        dataSorted = Utils.cloneData(data);

        ArrayList<RowData> subData1 = new ArrayList<>();
        ArrayList<RowData> subData2 = new ArrayList<>();
        for (RowData row : dataSorted) {
            if (getContValue(row.getRow().get(attrIndex)) < position) {
                subData1.add(row);
            } else {
                subData2.add(row);
            }

        }
        float gain = Entropy.calculateEntropy(dataSorted) - subData1.size() * Entropy.calculateEntropy(subData1) / (float) dataSorted.size()
                - subData2.size() * Entropy.calculateEntropy(subData2) / (float) dataSorted.size();
        return gain;
    }

    public static ArrayList<RowData> missValue(ArrayList<RowData> training_a, int attrIndex) {
        ArrayList<RowData> data = Utils.cloneData(training_a);
        String[] values = Constants.getMapAttrs()[attrIndex].getStringValues();
        int[] counts = new int[values.length];

        for (RowData row : data) {

            for (int i = 0; i < values.length; i++) {
                if (row.getRow().get(attrIndex).equalsIgnoreCase(values[i])) {
                    counts[i]++;
                    break;
                }
            }

        }
        int max = 0;
        for (int i = 1; i < counts.length; i++) {
            if (counts[i] > counts[max]) {
                max = i;
            }
        }
        for (RowData row : data) {
            if (row.getRow().get(attrIndex).equalsIgnoreCase("?")) {
                row.getRow().set(attrIndex, values[max]);
            }

        }
        return data;
    }


}
